package com.bestcem.xm.user.controller;

import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.domain.web.XmResultJson;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.uitls.IpUtil;
import com.bestcem.xm.component.security.annotation.AuthIgnore;
import com.bestcem.xm.component.security.annotation.XmAuth;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.component.security.dto.TokenDTO;
import com.bestcem.xm.user.controller.vo.user.*;
import com.bestcem.xm.user.controller.vo.user.request.*;
import com.bestcem.xm.user.enums.BooleanStatusEnum;
import com.bestcem.xm.user.grpc.client.dto.WxCodeSessionIdDTO;
import com.bestcem.xm.user.service.UserAuthService;
import com.bestcem.xm.user.service.UserWxService;
import com.bestcem.xm.user.service.dto.user.*;
import com.bestcem.xm.user.util.business.UserJwtTokenUtil;
import com.bestcem.xm.user.util.business.UserUtil;
import com.bestcem.xm.user.util.convert.UserLoginConvert;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
 * 用户登录controller
 *
 * @author wangyunyun <yunyun.wang@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/1 14:30
 */
@RestController
@RequestMapping(value = "/")
public class UserLoginController {

    @Resource
    private UserLoginConvert userLoginConvert;

    @Autowired
    private UserAuthService userAuthService;

    @Autowired
    private UserJwtTokenUtil userJwtTokenUtil;

    @Autowired
    private UserUtil userUtil;

    //@Resource
    //private UserMessageSender userMessageSender;

    @Resource
    private UserWxService userWxService;

    /**
     * 注册账号-验证手机号和验证码
     *
     * @param validateVO 验证手机号和验证码请求对象
     * @return
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/3/4 14:30
     */
    @AuthIgnore
    @PostMapping("/user/v4/register/")
    public XmResultJson<String> validatePhoneAndCode(@RequestBody ValidatePhoneAndCodeVO validateVO) {
        // 验证手机号
        ServiceResult<String> result = userAuthService.validatePhoneAndCode(validateVO.getPhone(), validateVO.getVcode());
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(result.getData());
    }

    /**
     * 注册账号-完善信息并注册
     *
     * @param orgRegisterVO 公司注册vo
     * @return
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/3/1 14:30
     */
    @AuthIgnore
    @PostMapping(value = "/user/v4/org_info/")
    public XmResultJson<UserLoginVO> orgRegister(HttpServletRequest request, @RequestBody OrgRegisterVO orgRegisterVO) {
        // 注册逻辑处理
        OrgRegisterDTO orgRegisterDTO = userLoginConvert.orgRegisterVo2Dto(orgRegisterVO);
        orgRegisterDTO.setIpAddress(IpUtil.getIpAddress(request));
        ServiceResult<UserLoginDTO> result = userAuthService.orgRegister(orgRegisterDTO);
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(userLoginConvert.userLoginDto2Vo(result.getData()));
    }

    /**
     * 用户退出登录
     * python引用：apps_mysql.auth.handlers.AuthTokenLogout.post
     * * - "@decorators.render_json"
     * 退出登录接口，将当前jwttoken放入redis的blacklist中，两小时失效
     *
     * @return com.bestcem.xm.util.XmResultJson
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/03 14:18
     */
    @XmAuth
    @PostMapping("/authorize/logout/")
    public XmResultJson<Object> logout(HttpServletRequest request) {
        String authorization = request.getHeader("authorization");
        if (authorization.startsWith(UserJwtTokenUtil.TOKEN_HEADER)) {
            authorization = authorization.substring(UserJwtTokenUtil.TOKEN_HEADER.length());
        }
        // 将token加入jwt失效白名单中
        userJwtTokenUtil.setJwtInvalid(authorization);
        // 发送消息 与access_key过期时间一致
        //userMessageSender.publishUserLogout(authorization);
        return XmResultJson.success();
    }

    /**
     * 用户使用账号名、密码、org_code登录获取token信息
     * 获取jwt
     * python引用：apps_mysql.auth.handlers.AuthTokenViewHandler.post
     *
     * @param request 请求的参数信息
     * @return com.bestcem.xm.util.XmResultJson<com.bestcem.xm.user.controller.vo.user.RefreshTokenVO>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/29 10:59
     */
    @PostMapping("/authorize/token/")
    @AuthIgnore
    public XmResultJson<RefreshTokenVO> getToken(@RequestBody @Valid GetTokenVO request, HttpServletRequest servletRequest) {
        // 获取租户自定义code相关
        ServiceResult<String> corpCode = userUtil.getCorpCode(request.getOrgCode(), servletRequest.getServerName());
        if (!corpCode.isSuccess()) {
            return XmResultJson.fail(corpCode.getErrorData(), corpCode.getMsg());
        }

        // 获取jwt信息
        ServiceResult<RefreshTokenDTO> result = userAuthService.getToken(request.getUserName(), request.getPassword(),
                Boolean.TRUE.equals(request.getEncrypt()), corpCode.getData());
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(userLoginConvert.refreshTokenDto2Vo(result.getData()));
    }

    /**
     * 刷新jwt
     * python引用：apps_mysql.auth.handlers.AuthTokenRefreshViewHandler.post
     * * - “@decorators.render_json”
     *
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/03 15:54
     */
    @PostMapping("/authorize/token/refresh/")
    @XmAuth
    public XmResultJson<RefreshTokenVO> refreshToken() {
        // 获取当前的token信息
        TokenDTO currentToken = SecurityContextHolder.getToken();
        String userId = currentToken.getUserId();
        String orgCode = currentToken.getOrgCode();

        ServiceResult<RefreshTokenDTO> result = userAuthService.refreshToken(userId, orgCode);
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(userLoginConvert.refreshTokenDto2Vo(result.getData()));
    }

    /**
     * Bi-分享密码获取token接口
     * python引用：apps_mysql.auth.handlers.AuthTokenViewBiShareHandler
     * Argument:
     * share_id: bi_models.Share.oid
     * request_pwd: bi_models.Share.request_pwd
     * Returns:
     * bi_share_token信息
     * <p>
     * * - "@decorators.render_json"
     *
     * @param request 请求信息
     * @return com.bestcem.xm.util.XmResultJson<BiShareTokenResponseVO>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/29 17:15
     */
    @PostMapping("/authorize/bishare/token/")
    @AuthIgnore
    public XmResultJson<BiShareTokenResponseVO> bishareToken(@RequestBody BiShareTokenRequsetVO request) {
        ServiceResult<String> result = userAuthService.bishareToken(request.getShareId(), request.getPassword());
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(new BiShareTokenResponseVO(result.getData()));
    }

    /**
     * 联合登录 https://wiki.idiaoyan.cn/pages/viewpage.action?pageId=25210252
     * 获取问卷网用户信息登录倍市得账号
     * 1. 存在账号则登录
     * 2. 不错不存在账号则注册后登录
     * 3. 没有手机、微信unionID则跳转到注册页面不予用户自行注册后登录
     * <p>
     * 测试额外回归内容：
     * 1. 忘记密码
     * 2. 免费账号的试用时间等信息
     * <p>
     * python引用：apps_mysql.user.v3.wjw_login.LoginByWenJuanHandler.get
     *
     * @param code 账号的的唯一标识
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/03 20:06
     */
    @GetMapping("/user/v3/auth/wjw/callback")
    @AuthIgnore
    public XmResultJson<Void> wjwCallBack(@RequestParam("code") String code, HttpServletRequest request,
                                          HttpServletResponse response) {
        String serverName = request.getServerName();
        String protocol = request.getScheme();
        ServiceResult<WenJuanLoginResultDTO> loginResult = userAuthService.wenJuanLogin(code, serverName, protocol);
        if (loginResult.isSuccess() && Objects.nonNull(loginResult.getData())) {
            try {
                // 设置cookie
                List<Cookie> cookieList = loginResult.getData().getCookieList();
                if (CollectionUtils.isNotEmpty(cookieList)) {
                    for (Cookie cookie : cookieList) {
                        response.addCookie(cookie);
                    }
                }
                response.sendRedirect(loginResult.getData().getRedirectUrl());
            } catch (IOException e) {
                e.printStackTrace();
            }
            return XmResultJson.success();
        }
        return XmResultJson.fail(Integer.valueOf(loginResult.getErrorCode()), loginResult.getMsg());
    }

    /**
     * 根据orgUUid获取缓存信息
     * python引用：apps_mysql.user.v3.wjw_login.CacheOrgsHandler.get
     * ### 选择企业登录
     * <p>
     * 多公司需要用户选择公司后登录
     * <p>
     * 1. 多公司情况下问卷网登录会跳转到 `/connect-login`页面
     * <p>
     * 并设置cookie：
     * <p>
     * `wjw_login_bestcem_org_uuid`:用来获取步骤2中的公司列表
     * `wjw_login_bestcem_login_session_id`: 用来调用快速登录的中`session_id`
     * <p>
     * 2. 请求接口获取公司列表让用户选择
     * <p>
     * 新接口文档: https://rap2.idiaoyan.cn/organization/repository/editor?id=21&itf=1406
     * 展示公司列表，用户选择公司 `org_code` 进入步骤3
     * <p>
     * 3. 复用快速登录接口获取token信息
     * <p>
     * "/api/authorize/fast/org/token/", post , session_id, org_code
     * <p>
     * 登录成功
     * * - "@decorators.render_json"
     *
     * @param orgUuid orgUuid
     * @return com.bestcem.xm.util.XmResultJson<java.util.List < com.bestcem.xm.user.controller.vo.user.WjwOrganizationInfoVO>>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/05/29 12:57
     */
    @GetMapping("/user/v3/auth/wjw/orgs")
    @AuthIgnore
    public XmResultJson<WjwOrganizationInfoVOList> getWjwCacheOrgInfos(@RequestParam("org_uuid") String orgUuid) {
        if (StringUtils.isBlank(orgUuid)) {
            return XmResultJson.fail(ReqErrorCodeEnum.PARAM_LOST, "orgUuid不能为空");
        }

        // 根据orgUUid获取缓存信息
        ServiceResult<List<WjwOrganizationInfoDTO>> cacheOrgInfos = userAuthService.getWjwCacheOrgInfos(orgUuid);
        if (cacheOrgInfos.isSuccess() && Objects.nonNull(cacheOrgInfos.getData())) {
            List<WjwOrganizationInfoVO> wjwOrganizationInfos =
                    userLoginConvert.wjwOrganizationInfoDtosToVos(cacheOrgInfos.getData());
            return XmResultJson.success(new WjwOrganizationInfoVOList(wjwOrganizationInfos));
        }
        return XmResultJson.fail(Integer.valueOf(cacheOrgInfos.getErrorCode()), cacheOrgInfos.getMsg());
    }

    /**
     * 微信小程序 login 后获取并存储用户凭证
     * apps_mysql/auth/handlers.py:882
     *
     * @param requestVO 用户登录凭证
     *                  有效期五分钟）。开发者需要在开发者服务器后台调用 auth.code2Session，使用 code 换取 openid 和 session_key 等信息。
     *                  https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
     * @return com.bestcem.xm.util.XmResultJson<com.bestcem.xm.user.controller.vo.user.WxCodeSessionIdVO> session_id
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/05/28 23:34
     */
    @PostMapping("/authorize/wxminiprogram/code/")
    @AuthIgnore
    public XmResultJson<WxCodeSessionIdVO> wxCodeView(@RequestBody WxCodeRequestVO requestVO) {
        if (StringUtils.isBlank(requestVO.getCode())) {
            return XmResultJson.fail(ReqErrorCodeEnum.PARAM_LOST, "code is required");
        }

        ServiceResult<WxCodeSessionIdDTO> result = userWxService.getAndSaveWxSessionInfoByCode(requestVO.getCode());
        if (result.isSuccess()) {
            WxCodeSessionIdVO wxCodeSessionIdVO = new WxCodeSessionIdVO();
            wxCodeSessionIdVO.setSessionId(result.getData().getSessionId());
            wxCodeSessionIdVO.setOpenId(result.getData().getOpenId());
            return XmResultJson.success(wxCodeSessionIdVO);
        }
        return XmResultJson.fail(result.getErrorData(), result.getMsg());
    }

    /**
     * 登录成功完善公司信息
     * python引用：apps_mysql.user.v3.handlers.OrgInfoHandler.put
     * * - “@decorators.render_json“
     * * - ”@decorators.check_user_is_super”
     *
     * @param completeOrgInfo 完善信息
     * @param request         request
     * @return 完善结果
     * @author jishuo.yan <jishuo.yan@idiaoyan.com>
     * qiongyu.cui <qiongyu.cui@idiaoyan.com>
     * @date 2022/03/02 16:30
     */
    @PutMapping("/user/v3/org_info/")
    @XmAuth
    public XmResultJson<Void> completeOrgInfo(@RequestBody CompleteOrgInfoVO completeOrgInfo, HttpServletRequest request) {
        TokenDTO token = SecurityContextHolder.getToken();
        // 校验是超级管理员
        if (BooleanStatusEnum.NO.getStatus().equals(token.getSuperRole())) {
            return XmResultJson.fail(ResourceErrorCodeEnum.PERMISSION_DENY, "only superadmin can do this");
        }
        // 获取租户自定义code相关
        ServiceResult<String> corpCode = userUtil.getCorpCode(completeOrgInfo.getOrgCode(), request.getServerName());
        if (!corpCode.isSuccess()) {
            return XmResultJson.fail(corpCode.getErrorData(), corpCode.getMsg());
        }

        CompleteOrgInfoDTO completeOrgInfoDTO = userLoginConvert.completeOrgInfoVo2Dto(completeOrgInfo);
        completeOrgInfoDTO.setOrgId(token.getOrgId());
        completeOrgInfoDTO.setUserId(token.getUserId());
        completeOrgInfoDTO.setOrgCode(corpCode.getData());
        ServiceResult<Void> result = userAuthService.completeOrgInfo(completeOrgInfoDTO);
        if (result.isSuccess()) {
            return XmResultJson.success();
        }
        return XmResultJson.fail(result.getErrorData(), result.getMsg());
    }

    /**
     * 跳过完善公司信息
     * 登陆成功页面 跳过按钮
     * python引用：apps_mysql.user.v3.handlers.OrgInfoJumpHandler.put
     * * - “@decorators.render_json”
     * * - "@decorators.check_user_is_super"
     *
     * @return orglist 公司列表
     * @author jishuo.yan <jishuo.yan@idiaoyan.com>
     * qiongyu.cui <qiongyu.cui@idiaoyan.com>
     * @date 2022/03/02 16:30
     */
    @PutMapping("/user/v3/org_info/jump/")
    @XmAuth
    public XmResultJson<Void> jumpCompleteOrgInfo() {
        // 校验是否是超级管理员
        TokenDTO token = SecurityContextHolder.getToken();
        if (!BooleanStatusEnum.YES.getStatus().equals(token.getSuperRole())) {
            return XmResultJson.fail(ResourceErrorCodeEnum.PERMISSION_DENY, "only superadmin can do this");
        }

        ServiceResult<Void> result = userAuthService.jumpCompleteOrgInfo(token.getOrgId(), token.getUserId());
        if (result.isSuccess()) {
            return XmResultJson.success();
        }
        return XmResultJson.fail(result.getErrorData(), result.getMsg());
    }
}
